package com.baox.agridata.synchronous.util;

import com.baox.agridata.synchronous.entity.abutment.XDRBaseDataEntity;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@Slf4j
public class ObjectToQueryParamsUtil {


    public static String appKey = "25828bfb32487e140f8b47ebdb7773f4";


    public static Map<String, String> convertToQueryParams(String keyName, Object obj) {
        Map<String, String> resultMap = new HashMap<>();
        try {
            // 获取Java对象的字段和值
//            Map<String, Object> fields = getFields(obj);

            Map<String, Object> fields = new HashMap<>();
            fields.put(keyName, obj);

            //第一步：设所有发送或者接收到的数据为集合M，将集合M内非空参数值的参数按照参数名ASCII码从小到大排序（字典序），使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串stringA。
            //第二步：在stringA最后拼接上appkey和timestamp得到stringSignTemp字符串。appkey由平台提供,appkey是用于生成、验证签名的重要参数，请勿在接口中传递，timestamp为当前时间戳
            //第三步，将stringSignTemp进行base64编码得到stringBase64，并对stringBase64进行HMAC-SHA256运算，再将得到的所有字符转换为大写，得到signature值signValue。
            String timestamp = DateUtil.tenDigitTimestamp();
            String signature = sortAndFormatParams(fields, timestamp);
            resultMap.put("timestamp", timestamp);
            resultMap.put("signature", signature);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultMap;
    }


    public static String sortAndFormatParams(Map<String, Object> map, String timestamp) {
        List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(map.entrySet());
        //第一步
        // 1.对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序）
        Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
            public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
                return (o1.getKey()).compareToIgnoreCase(o2.getKey());
            }
        });
        // 2.使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串stringA。
        StringBuilder sortedString = new StringBuilder();
        for (Map.Entry<String, Object> entry : infoIds) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value != null) {
                sortedString.append(key).append("=").append(value).append("&"); // 拼接字段名和字段值
            }
        }
        //第二步
        //3.获取当前时间戳
        //4.签名原串拼接秘钥appkey和当前时间戳timestamp
        sortedString.append("appkey").append("=").append(appKey).append("&");
        sortedString.append("timestamp").append("=").append(timestamp);

        //第三步
        //5.对字符串内容进行base64编码
        byte[] bytes = sortedString.toString().getBytes(); // 将字符串转换为字节数组
        String encodedString = Base64.getEncoder().encodeToString(bytes); // 对字节数组进行Base64编码

        //6.并对stringBase64进行HMAC-SHA256运算
        String shaContent = hmacSHA256(encodedString, appKey);

        //7.再将得到的所有字符转换为大写，得到signature值signValue。
        String signature = shaContent.toUpperCase();

//        log.info("stringSignTemp:{}", sortedString.toString()); //第一步输出结果
//        log.info("stringBase64:{}", encodedString);   //第二步输出结果
//        log.info("signature:{}", signature);   //第三步输出结果
        return signature;
    }


    public static Map<String, Object> getFields(Object obj) {
        Map<String, Object> fields = new HashMap<>();
        // 获取Java对象的所有字段和值
        // 这里使用反射来获取字段和值，可以根据具体需求进行修改
        // 这里只是一个示例，假设Java对象的字段都是公有的
        for (java.lang.reflect.Field field : obj.getClass().getDeclaredFields()) {
            try {
                field.setAccessible(true);
                String fieldName = field.getName();
                Object fieldValue = field.get(obj);
                fields.put(fieldName, fieldValue);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return fields;
    }


    public static String hmacSHA256(String data, String secret) {
        try {
            // Create HMAC-SHA256 key from the given secret
            SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(), "HmacSHA256");

            // Get an instance of Mac object implementing HMAC-SHA256
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(secretKeySpec);

            // Calculate the HMAC value
            byte[] hmacBytes = mac.doFinal(data.getBytes());

            // Convert result into a hexadecimal string
            StringBuilder sb = new StringBuilder(hmacBytes.length * 2);
            for (byte b : hmacBytes) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
        }
    }


    public static void main(String[] args) {
        XDRBaseDataEntity xdrBaseDataEntity = new XDRBaseDataEntity();
        xdrBaseDataEntity.setAdcode(510105);
        xdrBaseDataEntity.setRegion("青羊区");
        xdrBaseDataEntity.setMonth("2024-01");
        xdrBaseDataEntity.setF1(1000);
        xdrBaseDataEntity.setF2(1000);
        xdrBaseDataEntity.setF3(1000);
        xdrBaseDataEntity.setF4(1000);
        xdrBaseDataEntity.setF5(1000);
        xdrBaseDataEntity.setF6(1000);
        xdrBaseDataEntity.setF7(1000);
        xdrBaseDataEntity.setF8(1000);
        xdrBaseDataEntity.setF9(1000);
        xdrBaseDataEntity.setF10(1000);
        xdrBaseDataEntity.setF11(1000);
//        convertToQueryParams(xdrBaseDataEntity);
    }


}
